#include "configweave.h"

#include <cstdio>
#include <iostream>
#include <string>
#if CFG_HAVE_STD_RANGES
#include <ranges>
#endif

using namespace cfg;

static void
print_error(const ConfigError & e)
{
    std::cerr << "[" << static_cast<int>(e.code) << "] " << e.message;
    if (!e.path.empty())
    {
        std::cerr << " path=";
#if CFG_HAVE_STD_RANGES
        for (char ch : e.path | std::views::join_with(std::string_view(".")))
        {
            std::cerr << ch;
        }
#else
        for (size_t i = 0; i < e.path.size(); ++i)
        {
            if (i > 0)
                std::cerr << ".";
            std::cerr << e.path[i];
        }
#endif
    }
    if (e.expected_type)
        std::cerr << " expected_type=" << static_cast<int>(*e.expected_type);
    if (e.actual_type)
        std::cerr << " actual_type=" << static_cast<int>(*e.actual_type);
    if (e.min_value)
        std::cerr << " min=" << *e.min_value;
    if (e.max_value)
        std::cerr << " max=" << *e.max_value;
    if (e.expected_pattern)
        std::cerr << " pattern=\"" << *e.expected_pattern << "\"";
    if (e.notes)
        std::cerr << " notes=\"" << *e.notes << "\"";
    std::cerr << "\n";
}

static std::string
create_file(const std::string & filename, const char * content)
{
    FILE * fp = std::fopen(filename.c_str(), "w");
    if (!fp)
        return {};
    std::fputs(content, fp);
    std::fclose(fp);
    return filename;
}

int
main()
{
    // 1) 构造一个通过多数校验的示例配置
    const char * ok_yaml = R"YAML(
svc:
  name: api
  port: 8080
mode: prod
db:
  host: localhost
  port: 5432
features: [a, b]
)YAML";
    const std::string ok_path = create_file("combinator_ok.yaml", ok_yaml);

    ConfigWeave cw_ok;
    cw_ok
        .from_file(ok_path)
        // all_of: required_key("/svc/name") AND number_in_range("svc.port", 1..65535)
        .all_of({ConfigWeave::SubValidator{"required_key", {{"path", "/svc/name"}}},
                 ConfigWeave::SubValidator{"number_in_range",
                                           {{"path", "svc.port"}, {"min", "1"}, {"max", "65535"}}}})
        // any_of: mode in {dev,stage} OR mode in {prod}
        .any_of(
            {ConfigWeave::SubValidator{"enum_in_set", {{"path", "mode"}, {"values", "dev,stage"}}},
             ConfigWeave::SubValidator{"enum_in_set", {{"path", "mode"}, {"values", "prod"}}}})
        // one_of: exactly one of (mode==prod, mode==dev)
        .one_of({ConfigWeave::SubValidator{"enum_in_set", {{"path", "mode"}, {"values", "prod"}}},
                 ConfigWeave::SubValidator{"enum_in_set", {{"path", "mode"}, {"values", "dev"}}}})
        // not: mode must NOT be debug
        .not_(ConfigWeave::SubValidator{"enum_in_set", {{"path", "mode"}, {"values", "debug"}}})
        // if_then_else: if required_key("svc.name") then array_length("features")>=2 else require
        // fallback
        .if_then_else(
            ConfigWeave::SubValidator{"required_key", {{"path", "svc.name"}}},
            ConfigWeave::SubValidator{"array_length", {{"path", "features"}, {"min_len", "2"}}},
            ConfigWeave::SubValidator{"required_key", {{"path", "fallback"}}});

    auto r_ok = cw_ok.run();
    if (!r_ok.errors.empty())
    {
        std::cerr << "[OK case] unexpected errors: " << r_ok.errors.size() << "\n";
        for (const auto & e : r_ok.errors)
            print_error(e);
    }
    else
    {
        std::cout << "[OK case] all combinator validators passed.\n";
    }

    // 2) 构造一个故意触发组合校验失败的示例配置
    const char * bad_yaml = R"YAML(
svc:
  port: -1
mode: debug
features: [a]
)YAML";
    const std::string bad_path = create_file("combinator_bad.yaml", bad_yaml);

    ConfigWeave cw_bad;
    cw_bad.from_file(bad_path)
        .all_of({ConfigWeave::SubValidator{"required_key", {{"path", "/svc/name"}}},
                 ConfigWeave::SubValidator{"number_in_range",
                                           {{"path", "svc.port"}, {"min", "1"}, {"max", "65535"}}}})
        .any_of(
            {ConfigWeave::SubValidator{"enum_in_set", {{"path", "mode"}, {"values", "dev,stage"}}},
             ConfigWeave::SubValidator{"enum_in_set", {{"path", "mode"}, {"values", "prod"}}}})
        .one_of({ConfigWeave::SubValidator{"enum_in_set", {{"path", "mode"}, {"values", "prod"}}},
                 ConfigWeave::SubValidator{"enum_in_set", {{"path", "mode"}, {"values", "dev"}}}})
        .not_(ConfigWeave::SubValidator{"enum_in_set", {{"path", "mode"}, {"values", "debug"}}})
        .if_then_else(
            ConfigWeave::SubValidator{"required_key", {{"path", "svc.name"}}},
            ConfigWeave::SubValidator{"array_length", {{"path", "features"}, {"min_len", "2"}}},
            ConfigWeave::SubValidator{"required_key", {{"path", "fallback"}}});

    auto r_bad = cw_bad.run();
    std::cerr << "[Bad case] errors: " << r_bad.errors.size() << "\n";
    for (const auto & e : r_bad.errors)
        print_error(e);

    return 0;
}